import json
import random
from pathlib import Path
from dataclasses import dataclass
from typing import NamedTuple,Dict,Literal,Tuple,cast

class PunchProfile(NamedTuple):
    choices: int
    threshold: int
    hit_damage: int
    block_damage: int

    pre_msg: str
    hit_msg: str
    blocker_msg: str

    knockout_possible: bool=False

    def is_hit(self):
        return random.randint(1,self.choices)<=self.threshold

@dataclass
class Player:
    name:str
    best:int
    weakness:int
    is_computer:bool
    punch_profiles:Dict[Literal[1,2,3,4],PunchProfile]
    damage:int=0
    score:int=0
    knockout:bool=False

    def get_punch_choice(self)->Literal[1,2,3,4]:
        if self.is_computer:
            return random.randint(1,4)
        punch=-1
        while punch not in [1,2,3,4]:
            print(f"{self.name}的招式是？")
            #加上是不是数字的判断
            punch=int(input())
        return punch

#击倒阈值
KNOCKOUT_THRESHOLD=35
#击晕信息
KNOCKOUT_COLD="{loser}被击晕了无法继续进行比赛，胜利者属于{winner}"
#获取选手的弱点信息
def get_vulnerability():
    print("Ta的弱点是？")
    #对于数字的判断
    return int(input())

#获取电脑的弱点信息
def get_opponent_stats()->Tuple[int,int]:
    opponent_best=0
    opponent_weakness=0
    while opponent_best==opponent_weakness:
        opponent_best=random.randint(1,4)
        opponent_weakness=random.randint(1,4)

    return opponent_best,opponent_weakness

#获取招式的基本信息
def read_punch_profiles(filepath:Path):
    with open(filepath,encoding='utf-8')as f:
        punch_profiles_dict=json.load(f)
    return{
        cast(Literal[1,2,3,4],int(key)):PunchProfile(**value)
        for key,value in punch_profiles_dict.items()
    }

def main()->None:
    print("拳击游戏")
    print("design by yuanjieyi")
    print("由yuanjieyi设计创造")
    print("202312060339")

    print("你的对手的名字是：")
    opponent_name=input()

    print("你的名字是：")
    player_name=input()

    print("不同的出拳策略 1 摆拳 2 平勾拳 3 上勾拳 4 刺拳")
    print("你擅长的招式是：")
    player_best=int(input)
    player_weakness=get_vulnerability()
    player=Player(
        name=player_name,
        best=player_best,
        weakness=player_weakness,
        is_computer=False,
        punch_profiles=read_punch_profiles(
            Path(__file__).parent/"player-profile.json"
        ),
    )

    opponent_best,opponent_weakness=get_opponent_stats()
    opponent=Player(
        name=opponent_name,
        best=opponent_best,
        weakness=opponent_weakness,
        is_computer=True,
        punch_profiles=read_punch_profiles(
            Path(__file__.parent)/"opponent-profile.json"
        ),
    )

    print(player)
    print(opponent)
    for round_number in (1,2,3):
        if player.knockout or opponent.knockout:
            break
        play_round(round_number,player,opponent)

    if player.knockout:
        print(KNOCKOUT_COLD.format(loser=player.name,winner=opponent.name))
    elif opponent.knockout:
        print(KNOCKOUT_COLD.format(loser=opponent.name,winner=player.name))
    elif opponent.score>player.score:
        print(f"{opponent.name}打败了{player.name}")
    else:
        print(f"{player.name}打败了{opponent.name}")

    print("\n\n游戏结束")
    print("感谢游玩")


def is_opponents_turn()->bool:
    return random.randint(1,10)>5

def play_round(round_number:int,player:Player,opponent:Player)->None:
    print(f"第{round_number}轮次。\n开始...\n")
    #如果有一方的分数>=2，则直接结束
    if opponent.score>=2 or player.score>=2:
        return

    for _action in range(7):
        if is_opponents_turn():
            punch=opponent.get_punch_choice()
            active=opponent
            passive=player
            opponents_turn=True
        else:
            punch=player.get_punch_choice()
            active=opponent
            opponents_turn=False

    #不用再区分是玩家攻击还是电脑攻击，只做谁主动谁被动的判断
        punch_profile=active.punch_profiles[punch]

        #如果选中的招式是擅长的招数则攻击+2
        if punch==active.best:
            active.damage=active.damage+2

        print(punch_profile.pre_msg.format(opponent=opponent,player=player))

        #如果对手不擅长这个招数，那么ta将总是被击中
        if passive.weakness==punch or punch_profile.is_hit():
            print(punch_profile.hit_msg.format(opponent=opponent,player=player))
            #判定是否存在直接击倒的可能性
            if punch_profile.knockout_possible and active.damage>KNOCKOUT_THRESHOLD:
                if opponents_turn and opponent.damage>KNOCKOUT_THRESHOLD:
                    player.knockout=True
                    break
                elif opponents_turn ==False and player.damage>KNOCKOUT_THRESHOLD:
                    opponent.knockout=True
                    break
            #如果不存在击倒可能性则记录伤害
            if opponents_turn==True:
                opponent.damage=opponent.damage+punch_profile.hit_damage
            else:
                player.damage+=punch_profile.hit_damage

        else:
            print(punch_profile.blocker_msg.format(opponent=opponent,player=player))
            #如果对面闪开了你的攻击，可能会因为你的攻击后摇太大对你造成反击
            if opponents_turn:
                player.damage+=punch_profile.block_damage
            else:
                opponent.damage+=punch_profile.block_damage
        #如果有人被击晕，直接结束比赛
        if player.knockout or opponent.knockout:
            break

    #这里的分数用伤害统计，不太合理并且每一局的伤害会累计到下一局，也就是说如果你第一局造成大量伤害，第二局没造成伤害也有可能获胜
    if player.damage>opponent.damage:
        print(f"{player.name}获得了第{round_number}场胜利")
    else:
        print(f"{opponent.name}获得了第{round_number}场胜利")


if __name__=="__main__":
    main()



